package luafrontend.interpreter;

import java.util.List;

import luafrontend.gen.ast.Chunk;
import luafrontend.gen.ast.FunctionDefExp;
import luafrontend.gen.ast.ParList;
import luafrontend.values.LuaFunction;
import luafrontend.values.LuaNil;
import luafrontend.values.LuaReturnValue;
import luafrontend.values.LuaTable;
import luafrontend.values.LuaValue;

public class InterpreterFunction extends LuaFunction {
	private final FunctionDefExp node;
	private final InterpreterState state;
	private final String debugName;
	private final LuaReturnValue retval = new LuaReturnValue();
	
	private boolean breakFlag;
	private int loopDepth;
	
	public InterpreterFunction(FunctionDefExp node, InterpreterState state, String debugName) {
		this.node = node;
		this.state = state;
		this.debugName = debugName;
		setEnvironment(state.getCurrentFunction().getEnvironment());
	}
	
	public InterpreterFunction(Chunk chunk, InterpreterState state, LuaTable env, String debugName) {
		node = new FunctionDefExp(new ParList(), chunk.getBody());
		this.state = state;
		this.debugName = debugName;
		setEnvironment(env);
	}
	
	public InterpreterState getState() {
		return state;
	}
	
	@Override
	public LuaReturnValue call(List<LuaValue> args) {
		state.enterFunction(this);
		
		node.getBody().interpret(state);
		
		if (state.getCurrentFunction() == this) { //in case we didn't get return statement
			state.leaveFunction();
		}
		
		assert (retval != null);
		return retval;
	}
	
	public void addReturnValue(LuaValue val) {
		retval.add(val);
	}

	public String getDebugName() {
		return debugName;
	}
	
	public boolean shouldBreak() {
		return breakFlag;
	}
	
	public void setBreak(boolean flag) {
		breakFlag = flag;
	}
	
	public boolean inLoop() {
		return loopDepth > 0;
	}
	
	public void enterLoop() {
		loopDepth += 1;
	}
	
	public void leaveLoop() {
		loopDepth -= 1;
	}
}
